package safeCommitter.core.view.main;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.util.IOpenEventListener;
import org.eclipse.jface.util.OpenStrategy;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ViewForm;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.ToolBar;

import safeCommitter.core.view.action.CompareResultAction;
import safeCommitter.core.view.action.OpenEditorAtLineAction;
import safeCommitter.test.report.SCTestResult;
import safeCommitter.utils.SCUtils;

public class FailureTraceView {

	private final Table table;

	private final Image m_stackIcon = SCViewUtils
			.createImage("icons/stkfrm_obj.gif");
	private final Image m_exceptionIcon = SCViewUtils
			.createImage("icons/exc_catch.gif");

	private final CompareResultAction fCompareAction;

	private SCTestResult fFailure;

	private String fInputTrace;

	public FailureTraceView(ViewForm parent, SCReportView reportView,
			ToolBar toolBar) {
		table = new Table(parent, SWT.SINGLE | SWT.V_SCROLL | SWT.H_SCROLL);
		OpenStrategy handler = new OpenStrategy(table);
		fCompareAction = new CompareResultAction(this);
		ToolBarManager failureToolBarmanager = new ToolBarManager(toolBar);
		failureToolBarmanager.add(fCompareAction);
		failureToolBarmanager.update(true);

		handler.addOpenListener(new IOpenEventListener() {
			public void handleOpen(SelectionEvent e) {
				if (table.getSelection().length != 0) {
					Action a = createOpenEditorAction(getSelectedText());
					if (a != null) {
						a.run();
					}
				}
			}
		});

	}

	private Action createOpenEditorAction(String traceLine) {
		try {
			String testName = traceLine;
			testName = testName.substring(0, testName.lastIndexOf('.'));
			if (testName.contains("(")) {
				testName = testName.substring(0, testName.lastIndexOf('.'));
			}

			int innerSeparatorIndex = testName.indexOf('$');
			if (innerSeparatorIndex != -1) {
				testName = testName.substring(0, innerSeparatorIndex);
			}

			String lineNumber = traceLine;
			lineNumber = lineNumber.substring(lineNumber.indexOf(':') + 1,
					lineNumber.lastIndexOf(')'));

			int line = Integer.valueOf(lineNumber).intValue();

			// fix for bug 37333
			String cuName = traceLine.substring(traceLine.lastIndexOf('(') + 1,
					traceLine.lastIndexOf(':'));

			return new OpenEditorAtLineAction(cuName, testName, line);

		} catch (NumberFormatException e) {
			;
		} catch (IndexOutOfBoundsException e) {
			;
		}

		return null;
	}

	private void updateTable(String trace) {
		if (trace == null || trace.trim().equals("")) { //$NON-NLS-1$
			clear();

			return;
		}
		trace = trace.trim();
		table.setRedraw(false);
		table.removeAll();
		fillTable(trace);
		table.setRedraw(true);
	}

	public void showFailure(SCTestResult failure) {
		// System.out.println("showFailure");
		if (null == failure) {
			fCompareAction.setEnabled(false);
			clear();
			return;
		}

		fFailure = failure;
		fCompareAction.setEnabled(true);
		String trace = failure.getStackTrace();

		if (fInputTrace == trace) {
			return;
		}
		fInputTrace = trace;
		updateTable(trace);
	}

	private void fillTable(String trace) {
		StringReader stringReader = new StringReader(trace);
		BufferedReader bufferedReader = new BufferedReader(stringReader);
		String line;

		try {

			// first line contains the thrown exception
			line = bufferedReader.readLine();
			if (line == null) {
				return;
			}

			TableItem tableItem = new TableItem(table, SWT.NONE);
			String itemLabel = line.replace('\t', ' ');
			tableItem.setText(itemLabel);
			tableItem.setImage(m_exceptionIcon);

			// the stack frames of the trace
			while ((line = bufferedReader.readLine()) != null) {
				itemLabel = line.replace('\t', ' ');
				if (itemLabel.startsWith(" at org.testng.Assert")
						|| itemLabel.startsWith(" at org.testng.AssertJUnit")) {
					continue;

				}
				tableItem = new TableItem(table, SWT.NONE);

				tableItem.setImage(m_stackIcon);
				tableItem.setText(itemLabel);
			}
		} catch (IOException e) {
			TableItem tableItem = new TableItem(table, SWT.NONE);
			tableItem.setText(trace);
		}
	}

	private String getSelectedText() {
		return table.getSelection()[0].getText();
	}

	public Composite getComposite() {
		return table;
	}

	public void clear() {
		table.removeAll();
		fFailure = null;
	}

	public Shell getShell() {
		return SCUtils.getShell();
	}

	public SCTestResult getFailedTest() {
		return fFailure;
	}
}
